﻿using DocumentFormat.OpenXml.Drawing.Diagrams;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Folding;
using LunarSF.SHomeWorkshop.LunarMarkdownEditor.PythonAnalysis;
using LunarSF.SHomeWorkshop.LunarMarkdownEditor.PythonHelp.CompleteKeywords;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{
    public class PythonEditBase : TextEditor
    {
        private static BitmapSource pythonKeywordIcon;
        public static BitmapSource PythonKeywordIcon { get => pythonKeywordIcon; }

        public static BitmapSource customKeywordIcon;
        public static BitmapSource CustomKeywordIcon { get => customKeywordIcon; }

        static PythonEditBase()
        {
            pythonKeywordIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/custom_keywordIcon.png"));
            customKeywordIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/python_keywordIcon.png"));
        }

        public PythonEditBase()
        {
            this.SnapsToDevicePixels = true;//避免折叠线模糊
            this.Background = Brushes.WhiteSmoke;
            RenderOptions.SetEdgeMode(this, EdgeMode.Aliased);

            this.WordWrap = true;
            this.Options.ShowEndOfLine = false;
            this.Options.ShowSpaces = false;
            this.Options.ShowTabs = false;
            this.Options.ShowColumnRuler = true;
            this.Options.ShowBoxForControlCharacters = true;
            this.ShowLineNumbers = true;

            this.TextArea.SelectionBorder = new Pen(Brushes.Transparent, 1);
            this.TextArea.SelectionBrush = new SolidColorBrush(Color.FromArgb(255, 145, 83, 0));  // Color.FromArgb(255, 240, 106, 0) 是那两条行高亮线色
            this.TextArea.SelectionCornerRadius = 0;

            this.PreviewKeyDown += PythonEditBase_PreviewKeyDown;

            #region 代码折叠处理Folding            
            if (Globals.MainWindow.SupportFolding)
            {
                // 与主 Markdown 编辑器折叠状态保持一致！
                // 机器性能不行的话，主 Markdown 编辑器难以支持，Python 编辑器也难以支持！
                StartFolding();
            }
            #endregion

            #region 自动完成
            this.TextArea.TextEntered += TextArea_TextEntered;
            this.TextArea.TextEntering += TextArea_TextEntering;
            #endregion

            #region 内置的自动完成列表
            // 添加 Python 关键字
            var pyKeyWords = new string[] {
                "False",
                "None",
                "True",
                "and",
                "as",
                "assert",
                "async",
                "await",
                "break",
                "class",
                "continue",
                "def",
                "del",
                "elif",
                "else",
                "except",
                "finally",
                "for",
                "from",
                "global",
                "if",
                "import",
                "in",
                "is",
                "lambda",
                "nonlocal",
                "not",
                "or",
                "pass",
                "raise",
                "return",
                "try",
                "while",
                "with",
                "yield",
            };
            foreach (var keyWord in pyKeyWords)
            {
                innerCompletionData.Add(new CustomCompletionData(keyWord, "Python 关键词", keyWord, " < (Python 关键词)", System.Windows.Media.Brushes.RoyalBlue)
                {
                    Image = pythonKeywordIcon,
                });
            }

            var customKeyWords = new string[] {
                // 这些纯粹是"脏活"，纯粹是为了方便添加的
                // "纯文本处理器","纯文本片段",  // 已经添加了相关类名提示
                // "活动编辑器","活动编辑器内核", // 这两个也已经添加了
                "文本", "编辑器", // "路径","文件路径","目录路径",
            };

            foreach (var keyWord in customKeyWords)
            {
                innerCompletionData.Add(new CustomCompletionData(keyWord, "常用词组", keyWord, " < (常用词组)", System.Windows.Media.Brushes.SeaGreen)
                {
                    Image = customKeywordIcon,
                });
            }

            // 无参数方法，直接完成替换
            //var customNoArgMethods = new string[]
            //{
            //    "格式文档管理器","创建段落","创建片段",
            //};

            //foreach (var keyWord in customNoArgMethods)
            //{
            //    var methodItem = new CustomCompletionData(keyWord, "常用方法", keyWord + "()");
            //    innerCompletionData.Add(methodItem);
            //}

            // 这里添加的是一些定义在 文本文件 中的关键词。
            if (CompleteInfoManager.SingleManager.CompletionDatas.Count <= 0)
            {
                CompleteInfoManager.SingleManager.ReloadCompleteKeywordInfos();
                CompleteInfoManager.SingleManager.BuildCompletionDataList();
            }

            foreach (var cdl in CompleteInfoManager.SingleManager.CompletionDatas)
            {
                cdl.Completed += Cdl_Completed;
                innerCompletionData.Add(cdl);
            }

            //添加常用词
            var pyCommonWords = new string[] {
                "main",
                "__main__",
                "self",
            };
            foreach (var commonWord in pyCommonWords)
            {
                innerCompletionData.Add(new CustomCompletionData(commonWord, "常用词组", commonWord, " < (常用词组)", System.Windows.Media.Brushes.SteelBlue)
                {
                    Image = pythonKeywordIcon,
                });
            }

            // inputText
            // documentText
            // ignoreTextChanging
            // pathToWorkspace
            // pathOfWorkspace
            // psArgs
            //     Ae       此行以后属于 psArgs.Ae 
            //     Ate
            //     GetAllFilePathsOfWorkspace()
            //     HtmlFileName
            //     HtmlFilePath
            //     MdFileInfo
            //     MdFileName
            //     MdFilePath

            var lmeArgs = @"inputText|documentText|ignoreTextChanging|pathToWorkspace|pathOfWorkspace|psArgs|psArgs.Ae|psArgs.Ate|GetAllFilePathsOfWorkspace()|HtmlFileName|HtmlFilePath|MdFileInfo|MdFileName|MdFilePath".Split(new char[] { '|', }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var lmeArg in lmeArgs)
            {
                var key = lmeArg.EndsWith("()") ? lmeArg.Substring(0, lmeArg.Length - 1) : lmeArg;
                innerCompletionData.Add(new CustomCompletionData(key, "调用脚本时传入的参数", lmeArg, " < (初始参数)", System.Windows.Media.Brushes.MediumOrchid)
                {
                    Image = customKeywordIcon,
                });
            }

            #endregion 内置的自动完成列表
        }

        #region 折叠

        void foldingUpdateTimer_Tick(object sender, EventArgs e)
        {
            if (Globals.MainWindow.SupportFolding == false) return;

            if (foldingStrategy != null && foldingManager != null)
            {
                foldingStrategy.UpdateFoldings(foldingManager, this.Document);
            }
        }

        DispatcherTimer foldingUpdateTimer = new DispatcherTimer();

        /// <summary>
        /// 提供这个属性是为了便于在选项卡“不在最前”时停止折叠计算，减少消耗。
        /// </summary>
        public DispatcherTimer FoldingUpdateTimer { get { return this.foldingUpdateTimer; } }

        public CustomFoldingManager FoldingManager
        {
            get { return foldingManager; }
        }

        CustomFoldingManager foldingManager = null;
        AbstractFoldingStrategy foldingStrategy = null;

        public AbstractFoldingStrategy FoldingStrategy
        {
            get { return foldingStrategy; }
        }

        public bool StopFolding()
        {
            try
            {
                if (foldingUpdateTimer.IsEnabled)
                {
                    foldingUpdateTimer.Stop();
                }

                if (foldingManager != null)
                {
                    CustomFoldingManager.Uninstall(foldingManager);
                }
                foldingUpdateTimer.Tick -= foldingUpdateTimer_Tick;

                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool StartFolding()
        {
            try
            {
                if (foldingStrategy == null)
                    foldingStrategy = new CustomFoldingStrategyForPython(this);

                foldingManager = CustomFoldingManager.Install(this.TextArea);

                foldingStrategy.UpdateFoldings(FoldingManager, this.Document);

                foldingUpdateTimer.Interval = TimeSpan.FromSeconds(0.05);//0.05=50毫秒。
                foldingUpdateTimer.Tick += foldingUpdateTimer_Tick;

                if (foldingUpdateTimer.IsEnabled == false)
                {
                    foldingUpdateTimer.Start();
                }
                return true;
            }
            catch
            {
                return false;
            }
        }


        /// <summary>
        /// 折叠插入点所在的可折叠区域。
        /// </summary>
        public void FoldSelectedBlock()
        {
            if (Globals.MainWindow.SupportFolding == false) return;

            ICSharpCode.AvalonEdit.Folding.FoldingSection folding = null;

            foreach (var i in this.FoldingManager.AllFoldings)
            {
                if (i.StartOffset <= this.SelectionStart &&
                    i.EndOffset >= this.SelectionStart + this.SelectionLength)
                {
                    if (folding == null)
                    {
                        folding = i;
                        continue;
                    }
                    else
                    {
                        if (folding.StartOffset < i.StartOffset)
                        {
                            folding = i;
                            continue;
                        }
                    }
                }
            }

            if (folding != null)
            {
                folding.IsFolded = !folding.IsFolded;
            }
        }

        #endregion

        private PythonEditor masterEditor;

        internal PythonEditor MasterEditor
        {
            get { return this.masterEditor; }
            set { this.masterEditor = value; }
        }

        private void Cdl_Completed(object sender, EventArgs e)
        {
            // 完成事件
            try
            {
                var item = sender as CustomCompletionData;

                if (string.IsNullOrEmpty(item.PrefixClassName) == false)
                {
                    if (item.BackSelectOffset.HasValue && item.BackSelectOffset.Value < item.CompleteText.Length)
                    {
                        var curSelStart = this.SelectionStart;
                        var leftCharIndex = curSelStart - item.CompleteText.Length - 1;
                        var leftChar = this.Document.GetText(leftCharIndex, 1);
                        if ((leftCharIndex >= 0 && leftChar != "."))
                        {
                            this.Document.Replace(curSelStart - item.CompleteText.Length, 0, item.PrefixClassName + ".");
                            this.Select(curSelStart + item.PrefixClassName.Length + 1 - item.BackSelectOffset.Value, 0);
                        }
                        else
                        {
                            this.Select(this.SelectionStart - item.BackSelectOffset.Value, 0);
                        }
                    }
                }
                else
                {
                    if (item.BackSelectOffset.HasValue && item.BackSelectOffset.Value < item.CompleteText.Length)
                    {
                        this.Select(this.SelectionStart - item.BackSelectOffset.Value, 0);
                    }
                }

                // 自动完成有筛选，只显示一条信息即可
                // 按 F2 需要显示多条信息！！
                var obsMark = "";
                if (item.IsObsoleting)
                {
                    obsMark = "(废弃的)";
                }
                this.masterEditor.ateArgsInfo.Text = obsMark + "【" + item.Text + "】" + "\r\n" + new string('-', Utils.Text.GetTextWidth(item.Text)) + "\r\n" + item.Description.ToString();
                this.masterEditor.tcBottom.SelectedIndex = 2;
            }
            catch (Exception ex)
            {
                var time = DateTime.Now;
                MasterEditor.tbxErr.AppendText($"\r\n\r\n[Exception At:{time.ToShortDateString()} {time.ToShortTimeString()}]{ex.Message}\r\n\r\n");
            }
        }

        #region 自动完成

        private List<ICompletionData> innerCompletionData = new List<ICompletionData>();

        public List<ICompletionData> InnerCompletionData
        {
            get { return innerCompletionData; }
        }

        public void HideCompleteWindow()
        {
            if (completionWindow == null) return;

            CompletionWindow.Close();
            completionWindow = null;
        }

        private void TextArea_TextEntering(object sender, TextCompositionEventArgs e)
        {
            try
            {
                #region 对部分全角字符的处理：连续输入两遍，转为一个半角

                if (e.Text == "（" && this.left_text.EndsWith("（") && this.SelectionLength == 0)
                {
                    this.Document.Replace(this.SelectionStart - 1, 1, "(");
                    e.Handled = true;
                    return;
                }

                if (e.Text == "）" && this.left_text.EndsWith("）") && this.SelectionLength == 0)
                {
                    this.Document.Replace(this.SelectionStart - 1, 1, ")");
                    e.Handled = true;
                    return;
                }

                if (e.Text == "】" && this.left_text.EndsWith("】") && this.SelectionLength == 0)
                {
                    this.Document.Replace(this.SelectionStart - 1, 1, "]");
                    e.Handled = true;
                    return;
                }

                if (e.Text == "【" && this.left_text.EndsWith("【") && this.SelectionLength == 0)
                {
                    this.Document.Replace(this.SelectionStart - 1, 1, "[");
                    e.Handled = true;
                    return;
                }

                if ((e.Text == "“" || e.Text == "”") &&
                    (this.left_text.EndsWith("“") || this.left_text.EndsWith("”")) && this.SelectionLength == 0)
                {
                    this.Document.Replace(this.SelectionStart - 1, 1, "\"");
                    e.Handled = true;
                    return;
                }

                if ((e.Text == "‘" || e.Text == "’") &&
                    (this.left_text.EndsWith("‘") || this.left_text.EndsWith("’")) && this.SelectionLength == 0)
                {
                    this.Document.Replace(this.SelectionStart - 1, 1, "\'");
                    e.Handled = true;
                    return;
                }

                #endregion

                if ((e.Text == "."/* || e.Text == " " || e.Text == ":"*/) && CompletionWindow != null && CompletionWindow.Visibility == Visibility.Visible)
                {
                    var selItem = CompletionWindow.CompletionList.SelectedItem;
                    if (selItem != null)
                    {
                        var line = this.Document.GetLineByOffset(this.SelectionStart);
                        if (line == null) return;
                        var currentOffsetInLine = this.SelectionStart - line.Offset;
                        var lineLeftText = this.Document.GetText(line.Offset, currentOffsetInLine);

                        var tailSpaceCount = 0;
                        for (int i = lineLeftText.Length - 1; i >= 0; i--)
                        {
                            if (lineLeftText[i] == ' ') { tailSpaceCount++; }
                            else break;
                        }

                        if (tailSpaceCount > 0)
                        {
                            lineLeftText = lineLeftText.TrimEnd(new char[] { ' ', });
                        }

                        var lastIndexOfInvalidateChar = -1;
                        for (int i = lineLeftText.Length - 1; i >= 0; i--)
                        {
                            var c = lineLeftText[i];
                            // if (c == '.') continue;  // 这句不能加，否则会把 . 之前的也替换掉。
                            if (IsValidateChar(c)) continue;

                            lastIndexOfInvalidateChar = i;
                            break;
                        }

                        var start = this.SelectionStart;
                        var length = this.SelectionLength;
                        if (lastIndexOfInvalidateChar >= 0)
                        {
                            start = line.Offset + lastIndexOfInvalidateChar + 1;
                            length = lineLeftText.Length - lastIndexOfInvalidateChar - 1 + tailSpaceCount;
                        }
                        else
                        {
                            var leftWhiteCharsCount = 0;
                            foreach (var lc in lineLeftText)
                            {
                                if (lc == ' ' || lc == '\t')
                                    leftWhiteCharsCount++;
                                else break;
                            }

                            start = line.Offset + leftWhiteCharsCount;
                            length = lineLeftText.Length - leftWhiteCharsCount;
                        }

                        selItem.Complete(this.TextArea, new AnchorSegment(this.TextArea.Document, start, length), e);

                        // 加个空格
                        this.TextArea.Document.Insert(this.SelectionStart, e.Text);

                        completionWindow.Close();
                        completionWindow = null;
                        e.Handled = true;
                    }

                    if (e.Text == "." || e.Text == " ")
                    {
                        ShowCompleteWindow(e);
                    }

                    return;
                }
            }
            catch (Exception ex)
            {
                LMessageBox.ShowWarning(ex.Message);
            }

            // 注意：与输入 Markdown 不同：输入 Python 代码时，即使变量名使用中文，
            // 也不是输入每个字都需要刷新自动完成列表的数据项的。
            // 大体上，只有这么几种情况需要刷新数据项：
            //     ①输入空格后
            //     ②输入标点后（如赋值号 = 或 运算符号后）
            //     ③输入某些 Python 关键词后（如 import、from、for 等）后
            //     ④输入句点符号后（这个是重点）
            //     ⑤输入左括号后（例如指定 class 的基类）

            // 全部在 TextArea_TextEntered 事件中处理。
            //var line = this.Document.GetLineByOffset(this.SelectionStart);
            //if (line == null) return;
            //var currentOffsetInLine = this.SelectionStart - line.Offset;
            //var lineLeftText = this.Document.GetText(line.Offset, currentOffsetInLine);

            //if (completionWindow == null)
            //{
            //    completionWindow = new CompletionWindow(this.TextArea)
            //    {
            //        MinHeight = 34,
            //        MinWidth = 100,
            //    };
            //}

            //IList<ICompletionData> data = CompletionWindow.CompletionList.CompletionData;

            //if (ShowBlankLineCompletion(line, lineLeftText, e.Text, ref data)) return;  // Python 允许嵌套方法
        }



        /// <summary>
        /// 处理 from xxx 或 import xxx 中对 xxx 的自动完成提示。
        /// </summary>
        private bool ShowFromOrImportCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            // from import 语句
            var regFrom = new Regex(@"^((from)|(import)) {1,}$");
            var matchFrom = regFrom.Match(lineLeftText + inputText);
            if (matchFrom.Success)
            {
                // 清除自动完成列表并重新添加其中的项目。
                data.Clear();

                var ipLibInfo = new DirectoryInfo(Globals.InstalledPath + "Lib\\");
                var files = ipLibInfo.GetFiles("*.py");
                foreach (var file in files)
                {
                    if (file.Name.StartsWith("_")) continue;

                    var shortName = file.Name.EndsWith(".py") ? file.Name.Substring(0, file.Name.Length - 3) : file.Name;
                    if (shortName == "clrtype")
                    {
                        // 放在这里可在省去排序。
                        // 这个要单独处理，在 IronPython Lib 目录中找不到对应模块文件，应该是内置的。
                        data.Add(new CustomCompletionData("clr", "引用 .net 程序集", "clr"));
                    }

                    data.Add(new CustomCompletionData(shortName, "可导入的 IronPython 模块", shortName));
                }

                var userPythonModelDirectory = new DirectoryInfo(Globals.PathOfPythonScripts);
                var userScriptFiles = userPythonModelDirectory.GetFiles("*.py");
                foreach (var userScriptFile in userScriptFiles)
                {
                    if (userScriptFile.Name.StartsWith("_")) continue;

                    var shortName = userScriptFile.Name.EndsWith(".py") ? userScriptFile.Name.Substring(0, userScriptFile.Name.Length - 3) : userScriptFile.Name;

                    data.Add(new CustomCompletionData(shortName, "可导入的 用户脚本 模块", shortName));
                }

                //TODO: 可引入的 IronPython 包，这个暂时不支持
                var directories = ipLibInfo.GetDirectories();
                foreach (var directory in directories)
                {
                    string initFilePath;

                    if (directory.FullName.EndsWith("\\"))
                    {
                        initFilePath = directory.FullName + "__init__.py";
                    }
                    else
                    {
                        initFilePath = directory.FullName + "\\__init__.py";
                    }

                    if (File.Exists(initFilePath))
                    {
                        data.Add(new CustomCompletionData(directory.Name, "可导入的 IronPython 包", directory.Name));
                    }
                }

                // 引入 LME 命名空间
                data.Add(new CustomCompletionData("LunarSF", "LME 命名空间前缀", "LunarSF"));

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 处理 from xxx import 中的 import 的提示。
        /// </summary>
        private bool ShowFromImportCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            // from import 语句
            var regFrom = new Regex(@"^from {1,}[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,} {1,}$");
            var matchFrom = regFrom.Match(lineLeftText + inputText);
            if (matchFrom.Success)
            {
                // 清除自动完成列表并重新添加其中的项目。
                data.Clear();

                data.Add(new CustomCompletionData("import", "Python 关键词", "import"));

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 处理 from xxx.yyy.zzz import abcd 中对 abcd 的提示。
        /// </summary>
        private bool ShowFromImportModelCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            var regFrom = new Regex(@"(?<=(^from {1,}))([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})(\.[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}){0,}(?= {1,}import {1,}$)");
            var matchFrom = regFrom.Match(lineLeftText + inputText);
            if (matchFrom.Success)
            {
                // 清除自动完成列表并重新添加其中的项目。
                data.Clear();

                var modelShortPath = matchFrom.Value.Replace(".", "\\");
                var libPath = Globals.InstalledPath + "Lib\\";
                var modelPath = libPath + modelShortPath + ".py";

                var pythonModelInfo = GetPythonModelInfo(modelShortPath);
                if (pythonModelInfo == null)
                {
                    if (File.Exists(modelPath) == false)
                    {
                        // 如果不是 IronPython 模块，则看是否用户自定义模块
                        modelPath = Globals.PathOfPythonScripts + modelShortPath + ".py";
                    }

                    if (File.Exists(modelPath))
                    {
                        pythonModelInfo = new PythonModelInfo()
                        {
                            ModelName = modelShortPath,
                            ModelPath = modelPath,
                        };
                        PythonModelInfo.ReadElementInfos(modelPath, ref pythonModelInfo);
                        pythonModelInfos.Add(pythonModelInfo);
                    }
                    else
                    {
                        // 在 IronPython 模块和当前用户脚本目录下都找不到，可能是 .net 程序集。
                        var clrReferenceLines = GetImportedClrReferenceLines(1, line.LineNumber - 1);
                        modelShortPath = modelShortPath.Replace("\\", ".");

                        foreach (var clrReferenceLine in clrReferenceLines)
                        {
                            if (Globals.AppFileName.ToLower().StartsWith(clrReferenceLine.ToLower() + ","))
                            {
                                // 通常是引用 LME 自身

                            }
                            //if (File.Exists(Globals.InstalledPath + clrReferenceLine + ".exe"))
                            //{

                            //}
                            // TODO: 为安全考虑，暂不支持引用外部动态链接库
                            //else if (File.Exists(Globals.InstalledPath + clrReferenceLine + ".dll"))
                            //{
                            //    // 引用运行目录下某个 dll

                            //}
                            else return false;  //TODO： 暂时不支持引用 .net 程序集
                            //{
                            //    // 引用 .net 程序集

                            //}
                        }
                    }
                }

                if (pythonModelInfo == null || pythonModelInfo.Elements.Count <= 0) return false;

                foreach (var element in pythonModelInfo.Elements)
                {
                    // if (element.ElementName.StartsWith("_")) continue;  // 以下划线开头的仅“标明”是个内部方法，但实际上仍可访问，所以不应该被屏蔽！

                    data.Add(new CustomCompletionData(element.ElementName, element.ElementType.ToString(), element.ElementName));
                }

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        private bool ShowFromImportPackageCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            // 处理 from xxx import yyy 语句
            var regFrom = new Regex(@"(?<=(^from {1,}))([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})(\.[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}){0,}\.(?= {1,}import {1,}$)");
            var matchFrom = regFrom.Match(lineLeftText + inputText);
            if (matchFrom.Success)
            {
                // 清除自动完成列表并重新添加其中的项目。
                data.Clear();

                var packageShortPath = matchFrom.Value.Replace(".", "\\");
                if (packageShortPath.EndsWith("\\") == false)
                    packageShortPath += "\\";
                var libPath = Globals.InstalledPath + "Lib\\";
                var packagePath = libPath + packageShortPath;

                //TODO: 要考虑 IronPython 包和用户包之间的关系

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 处理 clr.AddReference() 中对 AddReference 的提示
        /// </summary>
        private bool ShowClrAddReferenceCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            if (lineLeftText == "clr." && inputText == ".")
            {
                data.Clear();

                data.Add(new CustomCompletionData("AddReference", "引用 .net 类型的方法", "AddReference"));

                ShowCompletionWindow();
                return true;
            }
            else if (lineLeftText == "clr.AddReference(" && inputText == "(")
            {
                data.Clear();

                data.Add(new CustomCompletionData("\"LunarMarkdownEditor\"", "引用 LME", "\"LunarMarkdownEditor\""));

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 对类与命名空间的提示。
        /// </summary>
        private bool ShowLmeClassCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            if ((lineLeftText == "from LunarSF." || lineLeftText == "import LunarSF.") && inputText == ".")
            {
                data.Clear();

                data.Add(new CustomCompletionData("SHomeWorkshop", "引用 LME 命名空间", "SHomeWorkshop"));

                ShowCompletionWindow();
                return true;
            }
            else if ((lineLeftText == "from LunarSF.SHomeWorkshop." || lineLeftText == "import LunarSF.SHomeWorkshop.") && inputText == ".")
            {
                data.Clear();

                data.Add(new CustomCompletionData("LunarMarkdownEditor", "引用 LME 命名空间", "LunarMarkdownEditor"));

                ShowCompletionWindow();
                return true;
            }
            else if ((lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor." || lineLeftText == "import LunarSF.SHomeWorkshop.LunarMarkdownEditor.") && inputText == ".")
            {
                data.Clear();

                data.Add(new CustomCompletionData("Utils", "LME 工具类集", "Utils"));
                data.Add(new CustomCompletionData("Widgets", "LME 部件类集", "Widgets"));

                ShowCompletionWindow();
                return true;
            }
            else if (lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils " ||
                lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets ")
            {
                data.Clear();
                data.Add(new CustomCompletionData("import", "Python 关键字", "import"));

                ShowCompletionWindow();
                return true;
            }
            else if ((lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils import " && inputText == " ") ||
                (lineLeftText == "import LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils." && inputText == "."))
            {
                data.Clear();
                data.Add(new CustomCompletionData("HtmlTag", "LME 工具类", "LButton"));
                data.Add(new CustomCompletionData("LFile", "LME 工具类", "LButton"));
                data.Add(new CustomCompletionData("Speech", "LME 工具类", "Speech"));
                data.Add(new CustomCompletionData("Text", "LME 工具类", "Text"));

                // 在 IronPython 中调用 WebBrowser 的 LoadCompleted 事件不起作用，不建议使用。
                //data.Add(new CustomCompletionData("Text", "LME 工具类", "Web"));

                ShowCompletionWindow();
                return true;
            }
            else if ((lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets import " && inputText == " ") ||
                (lineLeftText == "import LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets." && inputText == "."))
            {
                data.Clear();
                data.Add(new CustomCompletionData("LButton", "LME 按钮类", "LButton"));
                data.Add(new CustomCompletionData("LWindow", "LME 窗口类", "LWindow"));

                ShowCompletionWindow();
                return true;
            }
            else if (lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor ")
            {
                data.Clear();
                data.Add(new CustomCompletionData("import", "Python 关键字", "import"));

                ShowCompletionWindow();
                return true;
            }
            else if ((lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor import " && inputText == " ") ||
                (lineLeftText == "import LunarSF.SHomeWorkshop.LunarMarkdownEditor." && inputText == "."))
            {
                // 只提供常用类的建议列表
                data.Clear();

                data.Add(new CustomCompletionData("BrushManager", "LME 常用工具类", "BrushManager"));
                data.Add(new CustomCompletionData("CheckBoxItem", "LME 常用部件类", "CheckBoxItem"));
                data.Add(new CustomCompletionData("ChinesePinYin", "LME 常用工具类", "ChinesePinYin"));
                data.Add(new CustomCompletionData("CustomMarkdownSupport", "LME 常用工具类", "CustomMarkdownSupport"));
                data.Add(new CustomCompletionData("Globals", "LME 常用工具类", "Globals"));
                data.Add(new CustomCompletionData("InputBox", "LME 常用部件类", "InputBox"));
                data.Add(new CustomCompletionData("LMessageBox", "LME 常用部件类", "LMessageBox"));
                data.Add(new CustomCompletionData("MainWindow", "LME 常用部件类", "MainWindow"));
                data.Add(new CustomCompletionData("MarkdownEditor", "LME 常用部件类", "MarkdownEditor"));
                data.Add(new CustomCompletionData("XmlTools", "LME 常用工具类", "XmlTools"));

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 对变量的提示。
        /// </summary>
        private bool ShowVariablesCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            if (string.IsNullOrWhiteSpace(lineLeftText)) return false;

            if (inputText == ".")
            {
                var fstBodyLineNumber = GetFirstNoneImportLineNumber();
                if (line.LineNumber < fstBodyLineNumber) return false;

                AnalysisImportedElements(1, fstBodyLineNumber);

                var lastIndexOfInvalidateChar = -1;
                for (int i = lineLeftText.Length - 1; i >= 0; i--)
                {
                    var c = lineLeftText[i];
                    if (c == '.') continue;
                    if (IsValidateChar(c)) continue;

                    lastIndexOfInvalidateChar = i;
                    break;
                }

                if (lastIndexOfInvalidateChar < 0 || lastIndexOfInvalidateChar >= lineLeftText.Length - 1) return false;

                var varMark = lineLeftText.Substring(lastIndexOfInvalidateChar + 1).Trim(new char[] { '.', });
                // 此时 varMark 应该形如 xxx.yyyy.ab 或者就是 xxx 等等

                if (varMark.IndexOf(".") >= 0)
                {
                    foreach (var ie in importedElements)
                    {
                        switch (ie.Type)
                        {
                            case ImportedElementType.PythonPackage:
                                // 提示包中下属的子包名、模块名
                                // 暂时不考虑 __init__.py 中公开的方法等情况
                                break;
                            case ImportedElementType.PythonModel:
                                // 提示下属的方法、全局变量、类等
                                break;
                            case ImportedElementType.DotNetNamespace:
                                // 提示下级命名空间或者类名
                                break;
                            case ImportedElementType.DotNetClass:
                                // 提示下属的成员（方法、属性、公开字段等）
                                break;
                        }
                    }
                }
                else
                {
                    // 就是当前文件中某个类，找出其成员并提示


                }
            }

            return false;
        }

        private bool CompletionDataExist(ref IList<ICompletionData> data, string key)
        {
            if (data == null) return false;

            foreach (var ci in data)
            {
                if (ci.Text == key) return true;
            }

            return false;
        }

        /// <summary>
        /// 鉴于全面实现智能感知实在太复杂，改为“提示文本片段”会容易实现得多。所以暂时就做这样的一个临时功能。
        /// </summary>
        private bool ShowPiecesCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            // 从当前行的前一行开始向前倒找
            if (line.LineNumber > 1)
            {
                data.Clear();

                // 内置变量名、Python 关键词等。
                foreach (var innerItem in innerCompletionData)
                {
                    data.Add(innerItem);
                }

                List<string> addedItems = new List<string>();
                var trimChars = new char[] { ' ', '\t', };

                var regPiece = new Regex(@"[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}");
                var regEnPiece = new Regex(@"[a-zA-Z][a-zA-Z0-9_]{0,}");

                for (int i = line.LineNumber; i >= 1; i--)
                {
                    var iLine = this.Document.GetLineByNumber(i);
                    var iText = this.Document.GetText(iLine.Offset, iLine.Length);
                    if (iText.TrimStart(trimChars).StartsWith("#"))
                    {
                        var iepMatches = regEnPiece.Matches(iText);
                        if (iepMatches.Count > 0)
                        {
                            foreach (Match ipm in iepMatches)
                            {
                                var tKey = ipm.Value;
                                if (Exists(data, tKey) || string.IsNullOrWhiteSpace(ipm.Value)) continue;

                                var newData = new CustomCompletionData(tKey, "文本片段", ipm.Value, " < (本地注释)", System.Windows.Media.Brushes.DarkMagenta);
                                data.Add(newData);
                            }
                        }
                    }
                    else
                    {
                        var ipMatches = regPiece.Matches(iText);
                        if (ipMatches.Count > 0)
                        {
                            foreach (Match ipm in ipMatches)
                            {
                                var tKey = ipm.Value;
                                if (Exists(data, tKey) || string.IsNullOrWhiteSpace(ipm.Value)) continue;

                                var newData = new CustomCompletionData(tKey, "文本片段或变量名", ipm.Value, " < (本地)", System.Windows.Media.Brushes.DodgerBlue);
                                data.Add(newData);
                            }
                        }
                    }
                }

                if (data.Count > 0)
                {
                    ShowCompletionWindow();
                    return true;
                }

                return false;
            }

            return false;
        }

        private bool Exists(IList<ICompletionData> data, string value)
        {
            if (data == null || data.Count <= 0) return false;
            foreach (ICompletionData id in data)
            {
                if (id.Text == value) return true;
            }
            return false;
        }

        /// <summary>
        /// 提示当前文件中的变量或类名或方法名.
        /// </summary>
        private bool ShowInnerVariablesCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            var trimedLeftText = lineLeftText.TrimEnd();
            if (string.IsNullOrWhiteSpace(trimedLeftText) == false)
            {
                if (trimedLeftText.EndsWith(" and") == false &&
                    trimedLeftText.EndsWith(" or") == false &&
                    trimedLeftText.EndsWith("*") == false &&
                    trimedLeftText.EndsWith("/") == false &&
                    trimedLeftText.EndsWith("+") == false &&
                    trimedLeftText.EndsWith("-") == false &&
                    trimedLeftText.EndsWith("%") == false &&
                    trimedLeftText.EndsWith("=") == false &&
                    trimedLeftText.EndsWith("<") == false &&
                    trimedLeftText.EndsWith(">") == false)
                    return false;
            }

            // 要注意对内置方法的提示 例如 len() 等。
            // 先处理当前文档中的变量

            // 从当前行的前一行开始向前倒找
            if (line.LineNumber > 1)
            {
                data.Clear();
                List<string> addedItems = new List<string>();

                var regVariablesLine = new Regex(@"(?<=(^[ \t]*))([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})( *(, {0,}([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})))*(?=( *[=]))");
                var regMethodLine = new Regex(@"(?<=(^[ \t]*def {1,}([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}) {0,}\( {0,}))([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})( *(, {0,}([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})))*(?=( *\)))");
                var currentLineLevel = GetLineLevel(lineLeftText);
                var levelPoint = currentLineLevel;
                var methodMatched = false;
                var myMethodLevel = -1;
                for (int i = line.LineNumber - 1; i >= 1; i--)
                {
                    var iLine = this.Document.GetLineByNumber(i);
                    var iText = this.Document.GetText(iLine.Offset, iLine.Length);
                    var iLevel = GetLineLevel(iText);
                    if (iLevel < 0) continue;

                    var ivMatch = regVariablesLine.Match(iText);
                    if (ivMatch.Success)
                    {
                        if (iLevel > levelPoint) continue;
                        else if (iLevel <= levelPoint)
                        {
                            var varsText = ivMatch.Value;
                            if (string.IsNullOrWhiteSpace(varsText)) continue;
                            var vars = varsText.Split(new char[] { ',', ' ', }, StringSplitOptions.RemoveEmptyEntries);
                            foreach (var v in vars)
                            {
                                if (addedItems.Contains(v) == false)
                                {
                                    data.Add(new CustomCompletionData(v + " < (本地变量)", "当前文件中的变量", v));
                                    addedItems.Add(v);
                                }
                            }
                            if (iLevel < levelPoint) levelPoint = iLevel;

                            continue;
                        }
                    }

                    if (myMethodLevel >= 0 && iLevel >= myMethodLevel && methodMatched) continue;

                    var iaMatch = regMethodLine.Match(iText);
                    if (iaMatch.Success)
                    {
                        if (iLevel > levelPoint) continue;
                        else if (iLevel <= levelPoint)
                        {
                            myMethodLevel = iLevel;
                            methodMatched = true;
                            var argsText = iaMatch.Value;
                            if (string.IsNullOrEmpty(argsText)) continue;
                            var args = argsText.Split(new char[] { ',', ' ', }, StringSplitOptions.RemoveEmptyEntries);
                            foreach (var a in args)
                            {
                                if (addedItems.Contains(a) == false)
                                {
                                    data.Add(new CustomCompletionData(a + " < (本地参数)", "参数", a));
                                    addedItems.Add(a);
                                }
                            }
                            if (iLevel < levelPoint) levelPoint = iLevel;

                            continue;
                        }
                    }
                }

                // 最后考虑当前行中有没有可以使用的变量
                if (string.IsNullOrWhiteSpace(lineLeftText) == false)
                {
                    var currentLineMatch = regVariablesLine.Match(lineLeftText);
                    if (currentLineMatch.Success)
                    {
                        var cVarsText = currentLineMatch.Value;
                        var cVars = cVarsText.Split(new char[] { ',', ' ', }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var c in cVars)
                        {
                            if (addedItems.Contains(c) == false)
                            {
                                data.Add(new CustomCompletionData(c + " < (局部变量)", "局部变量", c));
                                addedItems.Add(c);
                            }
                        }
                    }
                }

                if (data.Count > 0)
                {
                    ShowCompletionWindow();
                    return true;
                }

                return false;
            }

            return false;
        }

        private int GetLineLevel(string lineText)
        {
            if (string.IsNullOrWhiteSpace(lineText)) return -1;  // 无意义

            lineText = lineText.Replace("\t", "    ");
            var count = 0;
            foreach (var c in lineText)
            {
                if (c == ' ') count++;
                else break;
            }

            if (count % 4 == 0) return count / 4;

            return -1;
        }

        /// <summary>
        /// 提供 Python 关键字的自动提示。
        /// </summary>
        private bool ShowBlankLineCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            if (string.IsNullOrWhiteSpace(lineLeftText))
            {
                // 清除自动完成列表并重新添加其中的项目。
                data.Clear();
                ShowInnerVariablesCompletion(line, lineLeftText, inputText, ref data);
                foreach (var innerItem in innerCompletionData)
                {
                    data.Add(innerItem);
                }
                ShowCompletionWindow();
                return true;
            }

            return false;
        }

        private void ShowCompletionWindow()
        {
            if (enableAutoComplete)
            {
                CompletionWindow.Show();
                CompletionWindow.Closed += delegate
                {
                    completionWindow = null;
                };
            }
        }

        private void TextArea_TextEntered(object sender, TextCompositionEventArgs e)
        {
            // if (e.Text != ".") return;  // 太烦人了

            if (e.Text.Length == 1 && ":]})\'\"".Contains(e.Text))
            {
                HideCompleteWindow();
                return;  // 冒号是准备下一行了，不需要弹出候选窗口。2025.3.27
            }

            if (e.Text.Length == 1 && "([{".Contains(e.Text))
            {
                var rtxt = this.RightText;
                if (rtxt.StartsWith(" ") == false && rtxt.StartsWith("\t") == false)
                {
                    HideCompleteWindow();
                    return;
                }
            }

            try
            {
                if (e.Text.Length <= 0 || e.Text == "\r\n")
                {
                    if (completionWindow != null)
                    {
                        completionWindow.Close();
                        completionWindow = null;
                    }
                    return;
                }

                ShowCompleteWindow(e);
            }
            catch (Exception ex)
            {
                LMessageBox.ShowWarning(ex.Message);
            }
            // Do not set e.Handled=true.
            // We still want to insert the character that was typed.
        }

        private void ShowCompleteWindow(TextCompositionEventArgs e)
        {
            if (IsValidateChars(e.Text) == false)
            {
                var line = this.Document.GetLineByOffset(this.SelectionStart);
                if (line == null) return;

                var currentOffsetInLine = this.SelectionStart - line.Offset;
                var lineLeftText = this.Document.GetText(line.Offset, currentOffsetInLine);

                if (lineLeftText.StartsWith("#") || lineLeftText.Trim(new char[] { ' ', '\t', }).Length <= 0) return;

                completionWindow = new CompletionWindow(this.TextArea)
                {
                    MinHeight = 34,
                    MinWidth = 260,
                };

                IList<ICompletionData> data = CompletionWindow.CompletionList.CompletionData;

                // 根据情况生成自动完成窗口及其中的项目
                //if (ShowFromOrImportCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowFromImportCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowFromImportModelCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowClrAddReferenceCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowLmeClassCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowReporterCommandsCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowInnerVariablesCompletion(line, lineLeftText, e.Text, ref data)) return;
                if (ShowPiecesCompletion(line, lineLeftText, e.Text, ref data)) return;

                if (data.Count > 0)
                {
                    // 完成插入，销毁自动完成窗口
                    CompletionWindow.CompletionList.RequestInsertion(e);
                    CompletionWindow.Close();
                    completionWindow = null;
                }
                else
                {
                    if (CompletionWindow != null)
                    {
                        CompletionWindow.Hide();
                    }
                }
                return;
            }
        }

        /// <summary>
        /// 是否均为可用标识符。包括 _ 字母 英文 中文字符(Unicode 19968-40869)。
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        private bool IsValidateChars(string text)
        {
            if (string.IsNullOrWhiteSpace(text)) return false;
            if (text.Contains('\r') || text.Contains('\n') || text.Contains('\t') || text.Contains(' ')) return false;

            foreach (var c in text)
            {
                if (c == '_') continue;
                if (c >= '0' && c <= '9') continue;
                if (c >= 'a' && c <= 'z') continue;
                if (c >= 'A' && c <= 'Z') continue;
                var v = (int)c;
                if (v >= 19968 && v <= 40869) continue;  // \u4E00-\u9FA5

                return false;
            }

            return true;
        }

        /// <summary>
        /// 是否英文字母、数字、下划线字符或 \u4E00-\u9FA5 之间的汉字。
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private bool IsValidateChar(char c)
        {
            if (c == '_') return true;
            if (c >= '0' && c <= '9') return true;
            if (c >= 'a' && c <= 'z') return true;
            if (c >= 'A' && c <= 'Z') return true;
            var v = (int)c;
            if (v >= 19968 && v <= 40869) return true;  // \u4E00-\u9FA5

            return false;
        }

        private void PythonEditBase_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            bool isCtrl = false ||
                (Keyboard.GetKeyStates(Key.RightCtrl) & KeyStates.Down) > 0 ||
                (Keyboard.GetKeyStates(Key.LeftCtrl) & KeyStates.Down) > 0;

            bool isShift = false ||
                (Keyboard.GetKeyStates(Key.RightShift) & KeyStates.Down) > 0 ||
                (Keyboard.GetKeyStates(Key.LeftShift) & KeyStates.Down) > 0;

            bool isAlt = false ||
                (Keyboard.GetKeyStates(Key.RightAlt) & KeyStates.Down) > 0 ||
                (Keyboard.GetKeyStates(Key.LeftAlt) & KeyStates.Down) > 0;

            try
            {
                switch (e.Key)
                {
                    case Key.I://为什么在这里处理？因为avalonEdit已经绑死Alt+Up，使用Alt+Up不起任何作用。其实用覆盖 OnKeyDown() 方法的办法可以解决。
                        {
                            if (isCtrl)//移动到上一行的上方。
                            {
                                if (isShift)
                                {
                                    if (!isAlt) SwapWithPreviewLine();
                                }
                                e.Handled = true;
                            }
                            break;
                        }
                    case Key.K://为什么用这个？因为avalonEdit已经绑死Alt+Up，使用Alt+Up不起任何作用。其实用覆盖 OnKeyDown() 方法的办法可以解决。
                        {
                            if (isCtrl && isShift && !isAlt)//移动到下一行的下方。
                            {
                                SwapWithNextLine();

                                e.Handled = true;
                            }
                            break;
                        }
                    case Key.Back://BackSpace，退格键
                        {
                            if (!isCtrl && !isAlt)
                            {
                                if (isShift)
                                {
                                    //删除到行首
                                    var textArea = this.TextArea;
                                    if (textArea != null && textArea.IsKeyboardFocused)
                                    {
                                        var curLine = this.Document.GetLineByOffset(this.SelectionStart);
                                        var curLineText = this.Document.GetText(curLine.Offset, curLine.Length);

                                        var fstSelectedLine = this.Document.GetLineByOffset(this.SelectionStart);

                                        this.Select(fstSelectedLine.Offset, textArea.Selection.Length + (this.SelectionStart - fstSelectedLine.Offset));
                                        textArea.PerformTextInput("");

                                        e.Handled = true;
                                    }
                                }
                                else
                                {
                                    // 删除成对括号
                                    if (this.SelectedText.Length == 0)
                                    {
                                        var leftText = this.LeftText;
                                        var rightText = this.RightText;
                                        if (leftText.EndsWith("(") && rightText.StartsWith(")"))
                                        {
                                            this.Document.Replace(this.SelectionStart - 1, 2, "");
                                            e.Handled = true;
                                        }
                                    }
                                }
                            }
                            break;
                        }
                    case Key.Enter://回车键
                        {
                            if (isCtrl)
                            {
                                if (!isShift)
                                {
                                    //在当前行下方插入一个新行，并移动光标。
                                    AppendANewLine();
                                    e.Handled = true;
                                }
                            }
                            else
                            {
                                if (isShift)
                                {
                                    //在当前行上方插入一个新行，并移动光标。
                                    InsertANewLine();
                                    e.Handled = true;
                                }
                                else
                                {
                                    if (completionWindow != null && completionWindow.Visibility != Visibility.Visible)
                                    {
                                        completionWindow.CompletionList.SelectedItem = null;
                                        // 解决按 esc 表示取消自动完成，隐藏自动完成窗口后按回车仍然自动完成的问题。

                                        AppendANewLine(true);
                                        e.Handled = true;
                                    }
                                    else
                                    {
                                        e.Handled = BreakLine();
                                    }
                                }

                                //AvalonEdit有个默认行为：若一行文本以空格开头，无论在第一个非空格字符前按下回车，还是在这些空格前按下回车，
                                //新行开头都不会保留空格！！！
                            }
                            break;
                        }
                    case Key.V:
                        {
                            if (!isAlt && isShift && isCtrl)
                            {
                                if (PasteRegionalText())
                                {
                                    e.Handled = true;
                                }
                            }
                            break;
                        }
                    case Key.Tab://Tab键
                        {
                            if (!isCtrl && !isAlt)
                            {
                                if (isShift)
                                {
                                    if (JumpOverMarks(ref e, isShift)) return;
                                }
                                else
                                {
                                    //跳过反引号，用在：按Ctrl+`输入一对反引号并将插入点置于两个反引号之间，输入一些文本后直接跳过右反引号继续输入其它文本。
                                    //这比按两个组合方向按键跳过去或者按方向键跳过去更方便。
                                    //*号对与_对情形类似。

                                    if (completionWindow != null && completionWindow.Visibility != Visibility.Visible)
                                    {
                                        completionWindow.CompletionList.SelectedItem = null;
                                        // 解决按 esc 表示取消自动完成，隐藏自动完成窗口后按回车或Tab仍然自动完成的问题。
                                        this.Document.Replace(this.SelectionStart, 0, "\t");
                                        this.Select(this.SelectionStart + 1, 0);
                                    }
                                    else
                                    {
                                        if (JumpOverMarks(ref e, isShift)) return;
                                    }
                                }
                            }
                            break;
                        }
                    case Key.Z:
                        {
                            if (!isAlt)
                            {
                                if (!isShift && isCtrl)
                                {
                                    if (this.CanUndo) this.Undo();
                                    e.Handled = true;
                                }
                            }
                            break;
                        }
                    case Key.Y:
                        {
                            if (!isAlt && !isShift && isCtrl)
                            {
                                if (this.CanRedo) this.Redo();
                                e.Handled = true;
                            }
                            break;
                        }
                    case Key.C:
                        {
                            if (isCtrl && isShift && !isAlt)
                            {
                                if (this.SelectedText.Length <= 0)
                                {
                                    // 复制当前行到新行
                                    var selLine = this.Document.GetLineByOffset(this.SelectionStart);
                                    var selLineText = this.Document.GetText(selLine.Offset, selLine.Length);
                                    var oldSelOffset = this.SelectionStart - selLine.Offset;
                                    if (selLineText.EndsWith("\r\n"))
                                    {
                                        this.Select(selLine.EndOffset, 0);
                                        this.SelectedText = selLineText;
                                        this.Select(this.SelectionStart + oldSelOffset, 0);
                                    }
                                    else
                                    {
                                        this.Select(selLine.EndOffset, 0);
                                        this.SelectedText = "\r\n" + selLineText;
                                        this.Select(this.SelectionStart + oldSelOffset + 2, 0);
                                    }
                                    e.Handled = true;
                                }
                            }
                            break;
                        }
                    case Key.J:
                        {
                            if (isCtrl && !isShift && !isAlt)
                            {
                                ShowCompletionWindowManual(e);
                                e.Handled = true;
                            }
                            break;
                        }
                    case Key.E:
                        {
                            if (isCtrl && !isShift && !isAlt)
                            {
                                EnableAutoComplete = !EnableAutoComplete;
                            }
                            break;
                        }
                    case Key.OemQuestion:
                        {
                            if (isCtrl && !isShift && !isAlt)
                            {
                                CommentSelectedLines();
                            }
                            break;
                        }
                    case Key.Delete:
                        {
                            if (!isCtrl && !isShift && !isAlt)
                            {
                                if (this.SelectedText == "")
                                {
                                    var leftTxt = this.LeftText;
                                    var rightTxt = this.RightText;
                                    if ((LeftText.EndsWith("\"") && RightText.StartsWith("\"")) ||
                                        (LeftText.EndsWith("\'") && RightText.StartsWith("\'")) ||
                                        (LeftText.EndsWith("(") && RightText.StartsWith(")")) ||
                                        (LeftText.EndsWith("[") && RightText.StartsWith("]")) ||
                                        (LeftText.EndsWith("{") && RightText.StartsWith("}")))
                                    {
                                        this.Select(this.SelectionStart - 1, 2);
                                        this.SelectedText = "";

                                        EnableAutoComplete = true;

                                        e.Handled = true;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                }
            }
            catch (Exception ex)
            {
                LMessageBox.Show("发生意外错误，无法执行操作。建议保存文件并重启程序。\r\n" +
                    ex.Message + "\r\n" + ex.StackTrace, Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }

        public bool PasteRegionalText()
        {
            try
            {
                var txt = Clipboard.GetData(DataFormats.Text) as string;
                if (string.IsNullOrEmpty(txt) == false)
                {
                    txt = "r'" + txt + "'";
                    this.Paste(txt);
                    this.Select(this.SelectionStart + txt.Length, 0);
                    return true;
                }

                return false;
            }
            catch (Exception ex)
            {
                LMessageBox.ShowWarning(ex.Message);
                return false;
            }
        }

        internal void CommentSelectedLines()
        {
            var fstLine = this.Document.GetLineByOffset(this.SelectionStart);
            var lastLine = this.Document.GetLineByOffset(this.SelectionStart + this.SelectionLength);

            var oldSel = this.SelectionStart;
            var oldSelLen = this.SelectionLength;

            var count = 0;
            for (int i = lastLine.LineNumber; i >= fstLine.LineNumber; i--)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);
                this.Document.Replace(line.Offset, line.Length, "# " + lineText);
                count += 2;
            }

            if (fstLine.LineNumber == lastLine.LineNumber)
            {
                this.Select(oldSel + 2, oldSelLen);
            }
            else
            {
                this.Select(oldSel + 2, oldSelLen + Math.Max(0, count - 2));
            }
        }

        /// <summary>
        /// 是否启用自动完成。
        /// </summary>
        private bool enableAutoComplete = true;

        public bool EnableAutoComplete
        {
            get { return this.enableAutoComplete; }
            set
            {
                this.enableAutoComplete = value;
                RefreshEnableAutoComplete();
            }
        }

        private void RefreshEnableAutoComplete()
        {
            if (this.enableAutoComplete == false)
            {
                if (this.completionWindow != null && this.completionWindow.Visibility == Visibility.Visible)
                {
                    this.completionWindow.Close();
                }
            }

            OnEnableAutoCompleteChanged(new EnableAutoCompleteEventArgs() { NewValue = this.enableAutoComplete });

            if (this.enableAutoComplete)
            {
                ShowCompletionWindowManual(null);
            }
        }

        public EventHandler<EnableAutoCompleteEventArgs> EnableAutoCompleteChanged;

        protected void OnEnableAutoCompleteChanged(EnableAutoCompleteEventArgs e)
        {
            if (EnableAutoCompleteChanged != null)
            {
                EnableAutoCompleteChanged(this, e);
            }
        }

        internal void ShowCompletionWindowManual(EventArgs e)
        {
            var line = this.Document.GetLineByOffset(this.SelectionStart);
            if (line == null) return;

            var currentOffsetInLine = this.SelectionStart - line.Offset;
            var lineLeftText = this.Document.GetText(line.Offset, currentOffsetInLine);

            if (lineLeftText.StartsWith("#")/* || lineLeftText.Trim(new char[] { ' ', '\t', }).Length <= 0*/) return;

            completionWindow = new CompletionWindow(this.TextArea)
            {
                MinHeight = 34,
                MinWidth = 260,
            };

            IList<ICompletionData> data = CompletionWindow.CompletionList.CompletionData;

            // 根据情况生成自动完成窗口及其中的项目
            //if (ShowFromOrImportCompletion(line, lineLeftText, e.Text, ref data)) return;
            //if (ShowFromImportCompletion(line, lineLeftText, e.Text, ref data)) return;
            //if (ShowFromImportModelCompletion(line, lineLeftText, e.Text, ref data)) return;
            //if (ShowClrAddReferenceCompletion(line, lineLeftText, e.Text, ref data)) return;
            //if (ShowLmeClassCompletion(line, lineLeftText, e.Text, ref data)) return;
            //if (ShowReporterCommandsCompletion(line, lineLeftText, e.Text, ref data)) return;
            //if (ShowInnerVariablesCompletion(line, lineLeftText, e.Text, ref data)) return;
            if (ShowPiecesCompletion(line, lineLeftText, " ", ref data)) return;

            if (data.Count > 0)
            {
                // 完成插入，销毁自动完成窗口
                CompletionWindow.CompletionList.RequestInsertion(e);
                CompletionWindow.Close();
                completionWindow = null;
            }
            else
            {
                if (CompletionWindow != null)
                {
                    CompletionWindow.Hide();
                }
            }
        }

        private CompletionWindow completionWindow;
        /// <summary>
        /// 自动完成窗口。
        /// </summary>
        public CompletionWindow CompletionWindow
        {
            get
            {
                return completionWindow;
            }
        }

        private List<PythonModelInfo> pythonModelInfos = new List<PythonModelInfo>();

        private PythonModelInfo GetPythonModelInfo(string pyModelName)
        {
            if (string.IsNullOrWhiteSpace(pyModelName)) return null;

            foreach (var pi in pythonModelInfos)
            {
                if (pi.ModelName != null && pi.ModelName == pyModelName)
                    return pi;
            }
            return null;
        }


        /// <summary>
        /// 取 import clr 语句所在的行号（从1开始），如果小于等于0，则表示从“当前行向前的所有行中都没有找到”。
        /// </summary>
        private int GetClrImportedLineNumber(DocumentLine curLine)
        {
            var regClrImported = new Regex(@"^import {1,}clr.*$");
            var trimChars = new char[] { ' ', };
            for (int i = 1; i < curLine.LineNumber; i++)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);
                if (string.IsNullOrWhiteSpace(lineText) || lineText.TrimStart(trimChars).StartsWith("#")) continue;
                if (regClrImported.Match(lineText).Success) return i;
            }
            return -1;
        }

        /// <summary>
        /// 取所有 cla.AddReference("xxx") 行。
        /// </summary>
        private List<string> GetImportedClrReferenceLines(int startLineNumber, int endLineNumber)
        {
            var resultList = new List<string>();
            var regClrAddReference = new Regex(@"(?<=(^clr.AddReference\([""']))([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})((\.[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}){0,})(?=([""']\)))");
            var trimChars = new char[] { ' ', };
            for (int i = startLineNumber; i <= endLineNumber; i++)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);
                if (string.IsNullOrWhiteSpace(lineText) || lineText.TrimStart(trimChars).StartsWith("#")) continue;
                var match = regClrAddReference.Match(lineText);
                if (match.Success)
                {
                    resultList.Add(match.Value);
                }
            }
            return resultList;
        }

        /// <summary>
        /// 取所有形如 from xxx.yyy.zzz import abcd as ef 这样的行。
        /// </summary>
        private List<string> GetFromImportedLine(int startLineNumber, int endLineNumber)
        {
            var resultList = new List<string>();
            var regFromImportLine = new Regex(@"(?<=(^from {1,})([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})(\.[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}) {1,}import {1,}([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})( {1,}as ([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})))");
            var trimChars = new char[] { ' ', };
            for (int i = startLineNumber; i <= endLineNumber; i++)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);
                if (string.IsNullOrWhiteSpace(lineText) || lineText.TrimStart(trimChars).StartsWith("#")) continue;
                var match = regFromImportLine.Match(lineText);
                if (match.Success)
                {
                    resultList.Add(lineText);
                }
            }
            return resultList;
        }

        private List<string> GetImportedLine(int startLineNumber, int endLineNumber)
        {
            var resultList = new List<string>();
            var regImportLine = new Regex(@"(?<=(^import {1,})([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})(\.[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}) {1,}import {1,}([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}))");
            var trimChars = new char[] { ' ', };
            for (int i = startLineNumber; i <= endLineNumber; i++)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);
                if (string.IsNullOrWhiteSpace(lineText) || lineText.TrimStart(trimChars).StartsWith("#")) continue;
                var match = regImportLine.Match(lineText);
                if (match.Success)
                {
                    resultList.Add(lineText);
                }
            }
            return resultList;
        }

        /// <summary>
        /// 由 from 和 import 引入的 .net 名字空间
        /// </summary>
        private List<ImportedElement> importedElements = new List<ImportedElement>();

        /// <summary>
        /// 刷新所有使用 import 和 from 语句引入的库。
        /// </summary>
        private void AnalysisImportedElements(int startLineNumber, int endLineNumber)
        {
            importedElements.Clear();
            if (endLineNumber < 1) return;

            var trimChars = new char[] { ' ', '　', '\t', };

            var fromLines = GetFromImportedLine(1, endLineNumber);
            foreach (var line in fromLines)
            {
                var indexOfAs = line.IndexOf(" as ");
                var elementText = "";
                var alias = "";
                if (indexOfAs >= 0)
                {
                    elementText = line.Substring(0, indexOfAs);
                    alias = line.Substring(indexOfAs + 4);
                }

                var newElement = new ImportedElement()
                {
                    Text = elementText,
                    Alias = alias,
                };
                newElement.Type = GetImportedElementType(elementText);
                importedElements.Add(newElement);
            }

            var importLines = GetImportedLine(1, endLineNumber);
            foreach (var line in importLines)
            {
                var elementText = line.Trim(trimChars);
                var newElement = new ImportedElement()
                {
                    Text = elementText,
                };
                newElement.Type = GetImportedElementType(elementText);
                importedElements.Add(newElement);
            }
        }

        private ImportedElementType GetImportedElementType(string elementText)
        {
            if (string.IsNullOrWhiteSpace(elementText)) return ImportedElementType.Unknown;

            // 先看是否 python 包
            var ironPythonLibPath = Globals.InstalledPath + "\\Lib\\";
            string shortPath;
            if (elementText.Contains("."))
            {
                shortPath = elementText.Replace(".", "\\");
            }
            else
            {
                shortPath = elementText;
            }
            shortPath.Trim(new char[] { '\\', '.', });
            if (Directory.Exists(ironPythonLibPath + shortPath)) return ImportedElementType.PythonPackage;

            // 再看是否 python 模块
            if (File.Exists(ironPythonLibPath + shortPath + ".py")) return ImportedElementType.PythonModel;

            // 为提高响应速度（也为了降低实现难度）关于 .net 的名字空间与类，仅提供 建议可用 的相关内容，并不完整。
            // 再看是否 .net 命名空间
            var trimedElementText = elementText.Trim(new char[] { '\\', '.', ' ', '　', '\t', });
            switch (trimedElementText)
            {
                case "LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils":
                case "LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets":
                case "LunarSF.SHomeWorkshop.LunarMarkdownEditor":
                    return ImportedElementType.DotNetNamespace;
            }

            // 再看是否 .net 类
            if (trimedElementText.StartsWith("LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils.") ||
                trimedElementText.StartsWith("LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets.") ||
                trimedElementText.StartsWith("LunarSF.SHomeWorkshop.LunarMarkdownEditor."))
                return ImportedElementType.DotNetClass;

            return ImportedElementType.Unknown;
        }

        /// <summary>
        /// 查找第一个非 import 且非 from 且非 注释 行且非 空白 行的行号。
        /// </summary>
        /// <returns>如果找不到，则返回 -1。</returns>
        private int GetFirstNoneImportLineNumber()
        {
            var trimChars = new char[] { ' ', };
            for (int i = 1; i <= this.Document.LineCount; i++)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);

                if (string.IsNullOrWhiteSpace(lineText)) continue;
                if (lineText.Trim(trimChars).StartsWith("#")) continue;
                if (lineText.StartsWith("from ") || lineText.StartsWith("import ")) continue;
                return i;
            }
            return -1;
        }

        #endregion 自动完成


        /// <summary>
        /// 附加新行。
        /// </summary>
        private bool BreakLine()
        {
            var selStartOffset = this.SelectionStart;
            var fstLine = this.Document.GetLineByOffset(selStartOffset);

            var selEndOffset = this.SelectionStart + this.SelectionLength;
            var lstLine = this.Document.GetLineByOffset(selEndOffset);

            var leftText = this.Document.GetText(fstLine.Offset, selStartOffset - fstLine.Offset);
            var midText = this.Document.GetText(selStartOffset, selEndOffset - selStartOffset);
            var rightText = this.Document.GetText(selEndOffset, lstLine.EndOffset - selEndOffset);

            if (leftText.TrimEnd(new char[] { ' ', }).EndsWith(":"))
            {
                var headerSpacesRegex = new Regex(@"^[\t ]{1,}");
                var headerSpacesMatch = headerSpacesRegex.Match(leftText);
                if (headerSpacesMatch.Success)
                {
                    this.Document.Replace(selStartOffset, selEndOffset - selStartOffset, "\r\n" + headerSpacesMatch.Value + "    ");
                    this.Select(fstLine.EndOffset + headerSpacesMatch.Length + 6, 0);
                }
                else
                {
                    this.Document.Replace(selStartOffset, selEndOffset - selStartOffset, "\r\n    ");
                    this.Select(fstLine.EndOffset + 6, 0);
                }
                return true;
            }

            return false;
        }

        /// <summary>
        /// 附加新行。
        /// </summary>
        private void AppendANewLine(bool withPrefixBlanks = false)
        {
            var curLine = this.Document.GetLineByOffset(this.SelectionStart + this.SelectionLength);
            var text = this.Document.GetText(curLine.Offset, curLine.Length);

            if (withPrefixBlanks)
            {
                var reg = new Regex(@"^[ \t]{1,}");
                var match = reg.Match(text);
                if (match.Success)
                {
                    this.Document.Insert(curLine.EndOffset, "\r\n" + match.Value);
                    this.Select(curLine.EndOffset + 2 + match.Length, 0);
                }
                else
                {
                    this.Document.Insert(curLine.EndOffset, "\r\n");
                    this.Select(curLine.EndOffset + 2, 0);
                }
            }
            else
            {
                this.Document.Insert(curLine.EndOffset, "\r\n");
                this.Select(curLine.EndOffset + 2, 0);
            }
        }

        /// <summary>
        /// 插入新行。
        /// </summary>
        private void InsertANewLine()
        {
            var curLine = this.Document.GetLineByOffset(this.SelectionStart);
            var text = this.Document.GetText(curLine.Offset, curLine.Length);

            this.Document.Insert(curLine.Offset, "\r\n");
            this.Select(curLine.Offset, 0);
        }

        /// <summary>
        /// 根据选项构建正则表达式。
        /// </summary>
        /// <param name="textToFind">要查找的文本</param>
        /// <param name="leftToRight">正序还是逆序。</param>
        private Regex GetRegEx(string textToFind, bool leftToRight)
        {
            RegexOptions options = RegexOptions.None;
            if (leftToRight)
            {
                options |= RegexOptions.RightToLeft;
            }
            options |= RegexOptions.IgnoreCase;

            string pattern = textToFind; // Regex.Escape(textToFind);
            return new Regex(pattern, options);
        }

        /// <summary>
        /// 跳转到下一个输入区域。这些输入区域包括：成对的小括弧之间，成对的大括弧之间，成对的中括弧之间等等。
        /// </summary>
        /// <param name="e"></param>
        private bool JumpOverMarks(ref KeyEventArgs e, bool isShift)
        {
            if (SelectionLength != 0) return false;
            //只有当插入点正好在某些特殊符号（及符号组合）前面时才起作用，用来跳过这些个特殊符号组合。

            try
            {
                var regexText = "(</?[a-zA-Z]{1,}( [^><]*)?>)|(\\*\\*)|(\\[\\=)|(\\=\\])|(__)|([ 　]*?[,，][ 　]*)|r[\"']|([_\\*“”‘’'\"`<>《》〈〉\\(\\)\\[\\]\\{\\}（）〔〕〈〉「」『』〖〗【】［］｛｝＂＇°])";

                Regex regex = GetRegEx(regexText, isShift);
                int start = regex.Options.HasFlag(RegexOptions.RightToLeft) ? SelectionStart : SelectionStart + SelectionLength;
                Match match = regex.Match(Text, start);

                if (!match.Success)  // start again from beginning or end
                {
                    if (regex.Options.HasFlag(RegexOptions.RightToLeft))
                        match = regex.Match(Text, Text.Length);
                    else
                        match = regex.Match(Text, 0);
                }

                if (match.Success)
                {
                    if (isShift)
                    {
                        if (match.Index + match.Length != SelectionStart) return false;

                        var destSel = match.Index;
                        if (destSel >= 0)
                        {
                            Select(destSel, 0);
                            TextLocation loc = Document.GetLocation(match.Index);
                            ScrollTo(loc.Line, loc.Column);

                            e.Handled = true;
                            return true;
                        }
                    }
                    else
                    {
                        if (match.Index != SelectionStart + SelectionLength) return false;

                        var destSel = match.Index + match.Length;
                        if (destSel <= Document.TextLength)
                        {
                            Select(destSel, 0);
                            TextLocation loc = Document.GetLocation(match.Index);
                            ScrollTo(loc.Line, loc.Column);

                            e.Handled = true;
                            return true;
                        }
                    }

                    return false;
                }

                return false;
            }
            catch (Exception ex)
            {
                LMessageBox.Show(ex.Message, Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return false;
            }
        }

        /// <summary>
        /// [覆盖方法]只有用这个办法才能使Alt+Up/Down生效。
        /// </summary>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.KeyboardDevice.Modifiers == ModifierKeys.Alt
                && (e.KeyboardDevice.IsKeyDown(Key.RightAlt) || e.KeyboardDevice.IsKeyDown(Key.LeftAlt)))
            {
                if ((e.Key == Key.Up || e.SystemKey == Key.Up))
                {
                    SwapWithPreviewLine();
                    e.Handled = true;
                }
                else if ((e.Key == Key.Down || e.SystemKey == Key.Down))
                {
                    SwapWithNextLine();
                    e.Handled = true;
                }
            }
            base.OnKeyDown(e);
        }

        /// <summary>
        /// 与后一行交换位置。
        /// </summary>
        internal void SwapWithNextLine()
        {
            var curStartLine = this.Document.GetLineByOffset(this.SelectionStart);
            var curEndLine = this.Document.GetLineByOffset(this.SelectionStart + this.SelectionLength);
            var nextLine = curEndLine.NextLine;

            if (nextLine != null)
            {
                this.BeginChange();
                var lineSplitter = "\n";
                if (this.Document.Text.Contains("\r\n"))
                {
                    lineSplitter = "\r\n";
                }
                var nextLineText = this.Document.GetText(nextLine.Offset, nextLine.Length);
                this.Document.Remove(nextLine.Offset - lineSplitter.Length, nextLine.Length + lineSplitter.Length);//先删除下一行

                var curStartLineOffset = curStartLine.Offset;
                this.Document.Insert(curStartLineOffset, nextLineText + lineSplitter);
                this.EndChange();
            }
        }

        /// <summary>
        /// 与前一行交换位置。
        /// </summary>
        internal void SwapWithPreviewLine()
        {
            var curStartLine = this.Document.GetLineByOffset(this.SelectionStart);
            var curEndLine = this.Document.GetLineByOffset(this.SelectionStart + this.SelectionLength);
            var preLine = curStartLine.PreviousLine;

            if (preLine != null)
            {
                this.BeginChange();
                var preStartLineOffset = preLine.Offset;
                var startOffset = this.SelectionStart - curStartLine.Offset;
                var selLength = this.SelectionLength;

                var lineSplitter = "\n";
                if (this.Document.Text.Contains("\r\n"))
                {
                    lineSplitter = "\r\n";
                }

                var preLineText = this.Document.GetText(preLine.Offset, preLine.Length);
                this.Document.Insert(curEndLine.EndOffset, lineSplitter);
                this.Document.Insert(curEndLine.EndOffset + lineSplitter.Length, preLineText);
                this.Document.Remove(preLine.Offset, preLine.Length + lineSplitter.Length);
                this.EndChange();

                this.Select(preStartLineOffset + startOffset, selLength);
            }
        }

        #region 便于 IronPython 脚本调用的方法

        /// <summary>
        /// SelectedText 的别名。
        /// </summary>
        public string seld { get { return this.SelectedText; } set { this.SelectedText = value; } }
        public string seld_txt { get { return this.SelectedText; } set { this.SelectedText = value; } }
        public string 选择的文本 { get { return this.SelectedText; } set { this.SelectedText = value; } }

        /// <summary>
        /// 活动文本文本，包括从 选择区头部所在行的头部 到 选择区尾部所在行 的尾部间的所有文本。
        /// 它一定是包含 SelectedText 的。
        /// </summary>
        public string actived_text
        {
            get
            {
                return this.Document.GetText(fst_doc_ln.Offset, lst_doc_ln.EndOffset - fst_doc_ln.Offset);
            }
        }
        public string actd_txt => actived_text;
        public string ActivedText => actived_text;
        public string 活动文本 { get { return actived_text; } }

        /// <summary>
        /// 取选择区到行首的文本
        /// </summary>
        public string LeftText
        {
            get
            {
                var selOffset = this.SelectionStart;
                var fstLine = this.Document.GetLineByOffset(selOffset);
                if (fstLine == null) return null;
                return this.Document.GetText(fstLine.Offset, selOffset - fstLine.Offset);
            }
        }
        /// <summary>
        /// LeftText 的别名。
        /// </summary>
        public string lt { get { return LeftText; } }
        public string l_txt { get { return LeftText; } }
        public string lt_txt { get { return LeftText; } }
        public string lft_txt { get { return LeftText; } }
        public string left_txt { get { return LeftText; } }
        public string left_text { get { return LeftText; } }
        public string 选择区左侧文本 { get { return LeftText; } }

        /// <summary>
        /// 取选择区尾到行尾的文本。
        /// </summary>
        public string RightText
        {
            get
            {
                var selEndOffset = this.SelectionStart + this.SelectionLength;
                var lastLine = this.Document.GetLineByOffset(selEndOffset);
                if (lastLine == null) return null;
                return this.Document.GetText(selEndOffset, lastLine.EndOffset - selEndOffset);
            }
        }
        /// <summary>
        /// RightText 的别名。
        /// </summary>
        public string rt { get { return RightText; } }
        public string r_txt { get { return RightText; } }
        public string rt_txt { get { return RightText; } }
        public string rgt_txt { get { return RightText; } }
        public string right_txt { get { return RightText; } }
        public string right_text { get { return RightText; } }
        public string 选择区右侧文本 { get { return RightText; } }

        /// <summary>
        /// 选择头。指选择区头到它所在行的行尾的文本。
        /// </summary>
        public string SelectedHead
        {
            get
            {
                var selOffset = this.SelectionStart;
                var fstLine = this.Document.GetLineByNumber(selOffset);
                if (fstLine == null) return null;
                return this.Document.GetText(selOffset, fstLine.EndOffset);
            }
        }
        /// <summary>
        /// SelectedHead 的别名。
        /// </summary>
        public string sdh { get { return SelectedHead; } }
        public string seld_head { get { return SelectedHead; } }
        public string selected_head { get { return SelectedHead; } }
        public string ht { get { return SelectedHead; } }
        public string hd_txt { get { return SelectedHead; } }
        public string head_txt { get { return SelectedHead; } }
        public string head_text { get { return SelectedHead; } }
        public string 选择区头到行尾 { get { return SelectedHead; } }

        /// <summary>
        /// 选定文本尾部到行首的文本。
        /// </summary>
        public string SelectedTail
        {
            get
            {
                var selEndOffset = this.SelectionStart + this.SelectionLength;
                var lstLine = this.Document.GetLineByOffset(selEndOffset);
                if (lstLine == null) return null;
                return this.Document.GetText(lstLine.Offset, selEndOffset - lstLine.Offset);
            }
        }
        /// <summary>
        /// SelectedTail 的别名。
        /// </summary>
        public string sdt { get { return SelectedTail; } }
        public string seld_tail { get { return SelectedTail; } }
        public string selected_tail { get { return SelectedTail; } }
        public string tt { get { return SelectedTail; } }
        public string tail_txt { get { return SelectedTail; } }
        public string tail_text { get { return SelectedTail; } }
        public string 选择区尾到行首 { get { return SelectedTail; } }

        /// <summary>
        /// 选择区第一行
        /// </summary>
        public DocumentLine first_document_line { get { return this.Document.GetLineByOffset(this.SelectionStart); } }
        /// <summary>
        /// first_line 别名。
        /// </summary>
        public DocumentLine fst_doc_ln { get { return first_document_line; } }
        /// <summary>
        /// 选择区最后一行。
        /// </summary>
        public DocumentLine last_document_line { get { return this.Document.GetLineByOffset(this.SelectionStart + this.SelectionLength); } }
        /// <summary>
        /// last_line 别名。
        /// </summary>
        public DocumentLine lst_doc_ln { get { return last_document_line; } }
        /// <summary>
        /// 选择区第一行文本。
        /// </summary>
        public string first_line
        {
            get
            {
                if (first_document_line == null || first_document_line.Offset < 0 || first_document_line.EndOffset >= this.Text.Length) return null;
                return this.Document.GetText(first_document_line.Offset, first_document_line.Length);
            }
        }
        /// <summary>
        /// first_line 别名。
        /// </summary>
        public string fst_ln { get { return first_line; } }
        public string 选择区头部所在行文本 { get { return first_line; } }

        /// <summary>
        /// 选择区最后一行文本。
        /// </summary>
        public string last_line
        {
            get
            {
                if (last_document_line == null || last_document_line.Offset < 0 || last_document_line.EndOffset >= this.Text.Length) return null;
                return this.Document.GetText(last_document_line.Offset, last_document_line.Length);
            }
        }
        /// <summary>
        /// last_line_text 别名。
        /// </summary>
        public string lst_ln { get { return last_line; } }
        public string 选择区尾部所在行文本 { get { return last_line; } }

        /// <summary>
        /// 选择区前一行。PreviewLine() 方法的别名。
        /// </summary>
        public DocumentLine preview_document_line
        {
            get
            {
                try
                {
                    var fst_line = this.Document.GetLineByOffset(this.SelectionStart);
                    return this.Document.GetLineByNumber(fst_line.LineNumber - 1);
                }
                catch { return null; }
            }
        }

        public DocumentLine pre_doc_ln => preview_document_line;

        /// <summary>
        /// 选择区前一行的文本。
        /// </summary>
        public string preview_line
        {
            get
            {
                if (preview_document_line == null) return null;
                return this.Document.GetText(preview_document_line.Offset, preview_document_line.Length);
            }
        }
        /// <summary>
        /// preview_line_text 别名。
        /// </summary>
        public string pre_ln { get { return preview_line; } }
        public string pl => preview_line;
        public string p_l => preview_line;
        public string 选择区头部前一行文本 { get { return preview_line; } }

        /// <summary>
        /// 选择区后一行。 NextLine() 方法的别名。
        /// </summary>
        public DocumentLine next_document_line
        {
            get
            {
                try
                {
                    var lst_line = this.Document.GetLineByOffset(this.SelectionStart + this.SelectionLength);
                    return this.Document.GetLineByNumber(lst_line.LineNumber + 1);
                }
                catch { return null; }
            }
        }
        /// <summary>
        /// next_line 别名。
        /// </summary>
        public DocumentLine nxt_doc_ln { get { return next_document_line; } }
        /// <summary>
        /// 选择区后一行的文本。
        /// </summary>
        public string next_line
        {
            get
            {
                if (next_document_line == null) return null;
                return this.Document.GetText(next_document_line.Offset, next_document_line.Length);
            }
        }
        /// <summary>
        /// next_line 别名。
        /// </summary>
        public string nxt_ln { get { return next_line; } }
        public string nl => next_line;
        public string n_l => next_line;
        public string 选择区尾部后一行文本 { get { return next_line; } }

        /// <summary>
        /// 选择文本。是 Select() 方法的别名。
        /// </summary>
        public void sel(int start, int length)
        {
            this.Select(start, length);
        }

        public void 选择文本(int start, int length)
        {
            this.Select(start, length);
        }

        /// <summary>
        /// 选取选择区起始位置到起始位置所在行行首之间的文本。
        /// </summary>
        public void SelectLeft()
        {
            var fstline = fst_doc_ln;
            this.Select(fstline.Offset, SelectionStart - fstline.Offset);
        }
        /// <summary>
        /// 选取选择区起始位置到起始位置所在行行首之间的文本。
        /// </summary>
        public void sel_left() => SelectLeft();
        public void sel_lft() => SelectLeft();
        public void 选择区头选到行首() => SelectLeft();

        /// <summary>
        /// 选取选择区开始位置到结束位置所在行行尾之间的文本。
        /// </summary>
        public void SelectRight()
        {
            var lstline = lst_doc_ln;
            this.Select(SelectionStart, lstline.EndOffset - SelectionStart);
        }
        /// <summary>
        /// 选取选择区开始位置到结束位置所在行行尾之间的文本。
        /// </summary>
        public void sel_right() => SelectRight();
        public void sel_rgt() => SelectRight();
        public void 选择区尾选到行尾() => SelectRight();

        /// <summary>
        /// 选取选择区头文本。
        /// </summary>
        public void SelectHead()
        {
            var fstline = fst_doc_ln;
            this.Select(SelectionStart, fstline.EndOffset - SelectionStart);
        }
        public void sel_head() => SelectHead();
        public void 选择区头选到行尾() => SelectHead();

        /// <summary>
        /// 选取选择区尾文本。
        /// </summary>
        public void SelectTail()
        {
            var lstline = lst_doc_ln;
            this.Select(lstline.Offset, SelectionStart + SelectionLength - lstline.Offset);
        }
        public void sel_tail() => SelectTail();
        public void 选择区尾选到行头() => SelectTail();

        /// <summary>
        /// 选择区头部索引。
        /// </summary>
        public int sel_start { get { return SelectionStart; } }
        public int 选择区头部索引 { get { return SelectionStart; } }

        /// <summary>
        /// 选择区尾部索引。
        /// </summary>
        public int SelectionEnd { get { return SelectionStart + SelectionLength; } }
        /// <summary>
        /// 选择区尾部索引别名。
        /// </summary>
        public int sel_end { get { return SelectionEnd; } }
        public int 选择区尾部索引 { get { return SelectionEnd; } }

        /// <summary>
        /// 选择区长度。
        /// </summary>
        public int sel_len { get { return SelectionLength; } }
        public int 选择区长度 { get { return SelectionLength; } }

        /// <summary>
        /// 选中前一行文本。
        /// </summary>
        /// <returns>如果不存在前一行，返回 false。</returns>
        public bool SelectPreviewLine()
        {
            try
            {
                if (preview_document_line == null) return false;
                this.Select(preview_document_line.Offset, preview_document_line.Length);
                return true;
            }
            catch { return false; }
        }
        public bool sel_pre_ln() => SelectPreviewLine();
        public bool 选择前一行文本() => SelectPreviewLine();

        /// <summary>
        /// 选中后一行文本。
        /// </summary>
        /// <returns>如果不存在后一行，返回 false。</returns>
        public bool SelectNextLine()
        {
            try
            {
                if (next_document_line == null) return false;
                this.Select(next_document_line.Offset, next_document_line.Length);
                return true;
            }
            catch { return false; }
        }
        public bool sel_nxt_ln() => SelectNextLine();
        public bool 选择后一行文本() => SelectNextLine();

        /// <summary>
        /// 选择区涉及到的所有行。
        /// </summary>
        public List<DocumentLine> selected_document_lines
        {
            get
            {
                try
                {
                    var list = new List<DocumentLine>();
                    for (int i = fst_doc_ln.LineNumber; i <= lst_doc_ln.LineNumber; i++)
                    {
                        list.Add(this.Document.GetLineByNumber(i));
                    }
                    return list;
                }
                catch { return null; }
            }
        }
        public List<DocumentLine> seld_doc_lns => selected_document_lines;
        /// <summary>
        /// 活动文本所涉及到的所有行——这种情况下它和 selected_document_line 的结果是相同的。
        /// 因为活动文本（active_text）是指从选择区头部延伸到所在行的头部，并从选择区尾部延伸到所在行尾部。
        /// </summary>
        public List<DocumentLine> actived_document_lines => selected_document_lines;
        public List<DocumentLine> actd_doc_lns => selected_document_lines;

        /// <summary>
        /// 选中的文本。
        /// </summary>
        /// <returns></returns>
        public string[] selected_lines
        {
            get
            {
                return this.SelectedText.Split(new string[] { "\r\n", }, StringSplitOptions.None);
            }
        }
        public string[] seld_lns => selected_lines;
        public string[] 选择的所有文本行 => selected_lines;

        public string[] actived_lines
        {
            get { return this.actived_text.Split(new string[] { "\r\n", }, StringSplitOptions.None); }
        }
        public string[] actd_lns => actived_lines;
        public string[] 活动的所有文本行 => actived_lines;

        public Tuple<int, int> 取行起始位置与长度(int lineNumber)
        {
            if (lineNumber < 1) lineNumber = 1;
            if (lineNumber > this.Document.LineCount) lineNumber = this.Document.LineCount;

            var dLine = this.Document.GetLineByNumber(lineNumber);
            return new Tuple<int, int>(dLine.Offset, dLine.Length);
        }

        public string 取文本(Tuple<int, int> tuple)
        {
            return this.Document.GetText(tuple.Item1, tuple.Item2);
        }

        public List<VarInfo> GetPreviewAsignLines(int curLineNumber, Regex regEx)
        {
            if (regEx == null) return null;
            if (curLineNumber <= 1 || curLineNumber > this.Document.LineCount) return null;

            var lines = new List<VarInfo>();

            var doubleMarks = new string[] { "<<", ">>", "//", "**", };
            var singleMarks = new string[] { "+", "-", "*", "/", "%", "&", "|", "^", };

            for (int i = curLineNumber - 1; i >= 1; i--)
            {
                var dLine = this.Document.GetLineByNumber(i);
                var dLineText = this.Document.GetText(dLine.Offset, dLine.Length);
                var match = regEx.Match(dLineText);
                if (match.Success)
                {
                    var asignMark = match.Value.Substring(match.Length - 2);
                    if (doubleMarks.Contains(asignMark))
                    {
                        lines.Add(new VarInfo(match, dLine, asignMark));
                    }
                    else
                    {
                        asignMark = match.Value.Substring(match.Length - 1);
                        if (singleMarks.Contains(asignMark))
                        {
                            lines.Add(new VarInfo(match, dLine, asignMark));
                        }
                        else
                        {
                            lines.Add(new VarInfo(match, dLine, ""));
                        }
                    }

                }
                else
                {
                    break;
                }
            }

            if (lines.Count <= 0) return null;

            return lines;
        }

        public List<VarInfo> GetNextAsignLines(int curLineNumber, Regex regEx)
        {
            if (regEx == null) return null;
            if (curLineNumber < 1 || curLineNumber >= this.Document.LineCount) return null;

            var lines = new List<VarInfo>();

            var doubleMarks = new string[] { "<<", ">>", "//", "**", };
            var singleMarks = new string[] { "+", "-", "*", "/", "%", "&", "|", "^", };

            for (int i = curLineNumber + 1; i <= this.Document.LineCount; i++)
            {
                var dLine = this.Document.GetLineByNumber(i);
                var dLineText = this.Document.GetText(dLine.Offset, dLine.Length);
                var match = regEx.Match(dLineText);
                if (match.Success)
                {
                    var asignMark = match.Value.Substring(match.Length - 2);
                    if (doubleMarks.Contains(asignMark))
                    {
                        lines.Add(new VarInfo(match, dLine, asignMark));
                    }
                    else
                    {
                        asignMark = match.Value.Substring(match.Length - 1);
                        if (singleMarks.Contains(asignMark))
                        {
                            lines.Add(new VarInfo(match, dLine, asignMark));
                        }
                        else
                        {
                            lines.Add(new VarInfo(match, dLine, ""));
                        }
                    }
                }
                else
                {
                    break;
                }
            }

            if (lines.Count <= 0) return null;

            return lines;
        }

        #endregion 便于 IronPython 脚本调用的方法
    }

    public class VarInfo
    {
        public VarInfo(Match match, DocumentLine documentLine, string assignPrefix)
        {
            this.VarMath = match;
            this.DocumentLine = documentLine;
            AssignPrefix = assignPrefix;
        }

        public string AssignPrefix { get; set; } = "";

        public Match VarMath { get; set; }

        public DocumentLine DocumentLine { get; set; }
    }

    public class EnableAutoCompleteEventArgs : EventArgs
    {
        public bool NewValue { get; set; }
    }
}
